/*
 * listest.c
 *
 *  Created on: Dec 18, 2014
 *      Author: Uzi
 */

#include "../mylist.h"
#include "test_utilities.h"
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>

int testAllocList() {
	linked_list_t** list;
	list = list_alloc();
	ASSERT_TEST(list != NULL);
	ASSERT_TEST(*list != NULL);
	list_free(&list);
	return 1;
}

int testInsert() {
	linked_list_t** list;
	list = list_alloc();
	ASSERT_TEST(list_insert(NULL, 3, NULL) != 0);
	ASSERT_TEST(list_insert(list, 3, NULL) == 0);
	ASSERT_TEST(list_insert(list, 5, NULL) == 0);
	ASSERT_TEST(list_contains(list, 3) == 1);
	ASSERT_TEST(list_insert(list, 3, NULL) != 0);
	ASSERT_TEST(list_insert(list, 1, NULL) == 0);
	ASSERT_TEST(list_insert(list, 8, NULL) == 0);
	ASSERT_TEST(list_insert(list, 4, NULL) == 0);
	ASSERT_TEST(list_insert(list, 6, NULL) == 0);
	list_free(&list);
	return 1;
}

int testRemove() {
	linked_list_t** list;
	list = list_alloc();

	list_insert(list, 1, NULL);
	list_insert(list, 3, NULL);
	list_insert(list, 5, NULL);
	list_insert(list, 7, NULL);

	ASSERT_TEST(list_remove(list, 1) == 0);
	ASSERT_TEST(list_remove(list, 1) != 0);

	ASSERT_TEST(list_remove(list, 5) == 0);
	ASSERT_TEST(list_remove(list, 5) != 0);

	ASSERT_TEST(list_insert(list, 5, NULL) == 0);
	ASSERT_TEST(list_remove(list, 5) == 0);

	ASSERT_TEST(list_remove(list, 7) == 0);
	ASSERT_TEST(list_remove(list, 7) != 0);

	ASSERT_TEST(list_remove(list, 3) == 0);
	ASSERT_TEST(list_remove(list, 3) != 0);

	list_free(&list);

	return 1;
}

int testContains() {
	linked_list_t** list;
	list = list_alloc();

	ASSERT_TEST(list_contains(list, 1) != 1);

	list_insert(list, 1, NULL);
	ASSERT_TEST(list_contains(list, 1) == 1);
	ASSERT_TEST(list_contains(list, 7) != 1);

	list_insert(list, 7, NULL);
	ASSERT_TEST(list_contains(list, 7) == 1);

	list_insert(list, 5, NULL);
	list_insert(list, 3, NULL);
	ASSERT_TEST(list_contains(list, 1) == 1);
	ASSERT_TEST(list_contains(list, 3) == 1);
	ASSERT_TEST(list_contains(list, 5) == 1);
	ASSERT_TEST(list_contains(list, 7) == 1);

	list_remove(list, 3);
	ASSERT_TEST(list_contains(list, 3) != 1);
	ASSERT_TEST(list_contains(list, 1) == 1);
	ASSERT_TEST(list_contains(list, 5) == 1);
	ASSERT_TEST(list_contains(list, 7) == 1);

	list_remove(list, 1);
	ASSERT_TEST(list_contains(list, 1) != 1);
	ASSERT_TEST(list_contains(list, 5) == 1);
	ASSERT_TEST(list_contains(list, 7) == 1);

	list_remove(list, 7);
	ASSERT_TEST(list_contains(list, 7) != 1);
	ASSERT_TEST(list_contains(list, 5) == 1);

	list_free(&list);

	return 1;
}

int testSize() {
	linked_list_t** list;
	list = list_alloc();

	ASSERT_TEST(list_size(list) == 0);

	list_insert(list, 1, NULL);
	ASSERT_TEST(list_size(list) == 1);

	list_insert(list, 7, NULL);
	ASSERT_TEST(list_size(list) == 2);

	list_insert(list, 5, NULL);
	ASSERT_TEST(list_size(list) == 3);

	list_insert(list, 3, NULL);
	ASSERT_TEST(list_size(list) == 4);

	list_remove(list, 7);
	ASSERT_TEST(list_size(list) == 3);

	list_remove(list, 1);
	ASSERT_TEST(list_size(list) == 2);

	list_insert(list, 4, NULL);
	ASSERT_TEST(list_size(list) == 3);

	list_remove(list, 4);
	ASSERT_TEST(list_size(list) == 2);

	list_free(&list);

	return 1;
}

void* computeGet(void* data) {
	return data;
}

int testUpdateCompute() {
	linked_list_t** list;
	list = list_alloc();

	int originalNum = 0;
	int newNum = 5;
	void* result;

	list_insert(list, 3, &originalNum);

	ASSERT_TEST(list_node_compute(list, 3, computeGet, &result) == 0);
	ASSERT_TEST(*(int* )result == originalNum);
	ASSERT_TEST(list_update_node(list, 3, &newNum) == 0);
	ASSERT_TEST(list_node_compute(list, 3, computeGet, &result) == 0);
	ASSERT_TEST(*(int* )result == newNum);
	ASSERT_TEST(list_update_node(list, 17, &newNum) != 0);
	ASSERT_TEST(list_node_compute(list, 11, computeGet, &result) != 0);

	int num[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	int updater[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	void* res[10];

	int i;

	for (i = 0; i < 10; i++) {
		list_insert(list, i, &num[i]);
	}

	for (i = 0; i < 10; i++) {
		ASSERT_TEST(list_update_node(list, i, &updater[9 - i]) == 0);
	}

	for (i = 0; i < 10; i++) {
		ASSERT_TEST(list_node_compute(list, i, computeGet, &res[i]) == 0);
	}

	for (i = 0; i < 10; i++) {
		ASSERT_TEST(*((int** )res)[i] == 10 - i);
	}

	list_free(&list);

	return 1;
}

int testBatchInsertRemove() {
	linked_list_t** list;
	list = list_alloc();

	op_t opArray[20];

	/*
	 * Testing concurrent inserts
	 */
	opArray[0].op = INSERT;
	opArray[0].index = 1;
	opArray[0].data = NULL;

	opArray[1].op = INSERT;
	opArray[1].index = 3;
	opArray[1].data = NULL;

	opArray[2].op = INSERT;
	opArray[2].index = 5;
	opArray[2].data = NULL;

	opArray[3].op = INSERT;
	opArray[3].index = 3;
	opArray[3].data = NULL;

	opArray[4].op = INSERT;
	opArray[4].index = 2;
	opArray[4].data = NULL;

	list_batch(list, 5, opArray);
	ASSERT_TEST(opArray[0].result == 0);
	ASSERT_TEST(opArray[2].result == 0);
	ASSERT_TEST(opArray[4].result == 0);
	ASSERT_TEST(((opArray[3].result == 0) || (opArray[1].result == 0)));
	ASSERT_TEST(((opArray[3].result == 1) || (opArray[1].result == 1)));

	ASSERT_TEST(list_size(list) == 4);
	ASSERT_TEST(list_contains(list, 1) == 1);
	ASSERT_TEST(list_contains(list, 2) == 1);
	ASSERT_TEST(list_contains(list, 3) == 1);
	ASSERT_TEST(list_contains(list, 5) == 1);
	ASSERT_TEST(list_contains(list, 4) != 1);

	/*
	 * Testing concurrent removes
	 */
	opArray[0].op = REMOVE;
	opArray[0].index = 9;
	opArray[0].data = NULL;

	opArray[1].op = REMOVE;
	opArray[1].index = 3;
	opArray[1].data = NULL;

	opArray[2].op = REMOVE;
	opArray[2].index = 3;
	opArray[2].data = NULL;

	opArray[3].op = REMOVE;
	opArray[3].index = 3;
	opArray[3].data = NULL;

	opArray[4].op = REMOVE;
	opArray[4].index = 2;
	opArray[4].data = NULL;

	list_batch(list, 5, opArray);

	ASSERT_TEST(list_size(list) == 2);
	ASSERT_TEST(opArray[0].result == 1);
	ASSERT_TEST(opArray[4].result == 0);
	ASSERT_TEST(
			opArray[1].result == 1 || opArray[2].result == 1
					|| opArray[3].result == 1);
	ASSERT_TEST(list_contains(list, 1) == 1);
	ASSERT_TEST(list_contains(list, 5) == 1);
	ASSERT_TEST(list_contains(list, 2) != 1);
	ASSERT_TEST(list_contains(list, 3) != 1);

	/*
	 * Testing concurrent and independent inserts/removes
	 */
	opArray[0].op = INSERT;
	opArray[0].index = 9;
	opArray[0].data = NULL;

	opArray[1].op = INSERT;
	opArray[1].index = 3;
	opArray[1].data = NULL;

	opArray[2].op = INSERT;
	opArray[2].index = 7;
	opArray[2].data = NULL;

	opArray[3].op = INSERT;
	opArray[3].index = 3;
	opArray[3].data = NULL;

	opArray[4].op = INSERT;
	opArray[4].index = 11;
	opArray[4].data = NULL;

	opArray[5].op = REMOVE;
	opArray[5].index = 10;
	opArray[5].data = NULL;

	opArray[6].op = INSERT;
	opArray[6].index = 0;
	opArray[6].data = NULL;

	opArray[7].op = REMOVE;
	opArray[7].index = 1;
	opArray[7].data = NULL;

	opArray[8].op = REMOVE;
	opArray[8].index = 5;
	opArray[8].data = NULL;

	opArray[9].op = REMOVE;
	opArray[9].index = 1;
	opArray[9].data = NULL;

	list_batch(list, 10, opArray);

	ASSERT_TEST(opArray[0].result == 0);
	ASSERT_TEST(opArray[2].result == 0);
	ASSERT_TEST(opArray[4].result == 0);
	ASSERT_TEST(((opArray[3].result == 0) || (opArray[1].result == 0)));
	ASSERT_TEST(((opArray[3].result == 1) || (opArray[1].result == 1)));
	ASSERT_TEST(opArray[5].result == 1);
	ASSERT_TEST(opArray[6].result == 0);
	ASSERT_TEST(opArray[7].result == 1 || opArray[9].result == 1);
	ASSERT_TEST(opArray[8].result == 0);
	ASSERT_TEST(list_contains(list, 1) == 0);
	ASSERT_TEST(list_contains(list, 5) == 0);
	ASSERT_TEST(list_contains(list, 9) == 1);
	ASSERT_TEST(list_contains(list, 11) == 1);
	ASSERT_TEST(list_contains(list, 0) == 1);
	ASSERT_TEST(list_contains(list, 3) == 1);
	ASSERT_TEST(list_size(list) == 5);

	//list_print(list);

	list_free(&list);

	return 1;
}

int testFree() {
	linked_list_t** list;
	int i = 0;
	list = list_alloc();

	op_t opArray[1500];
	for (; i < 100; i++) {
		opArray[i].op = INSERT;
		opArray[i].index = i;
		opArray[i].data = NULL;
		//list_insert(list, i, NULL);
	}
	list_batch(list, 1500, opArray);
	list_free(&list);
	return 1;
}
int main() {
	int i = 0;
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);
	RUN_TEST(testAllocList);
	RUN_TEST(testInsert);
	RUN_TEST(testRemove);
	RUN_TEST(testContains);
	RUN_TEST(testSize);
	RUN_TEST(testUpdateCompute);
	RUN_TEST(testBatchInsertRemove);
	RUN_TEST(testFree);
	return 0;
}

